//=====================================================================
// Win32Basic.cpp 
//
// The classic and undoubtedly naive example of Win32 code needed for
// programming a real-time game. It's in all the books but surely there's a 
// better, more flexible and less monolithic way?
//=====================================================================

// Include the Required headers, using the compilers precompiled headers
// feature to cut down on compile times

#include "Precompiled.h"

// The main window handle used to identify a created window.
HWND g_hMainWnd = 0;

// Function to wrap the code required to initialise a Windows
// application. Returns true if initialisation was successful,
// otherwise it returns false.
bool InitWindowsApp(HINSTANCE instanceHandle, int show);

// Functions that wraps the message loop code.
int  Run();

// The window procedure that handles events our window recieves.
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Windows main entry point. The equivalant to main()
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int nShowCmd)
{
	// Initialise the Windows application
	if(!InitWindowsApp(hInstance, nShowCmd))
		return 0;

	// Start the real-time message pump
	return Run();
}

#pragma region InitWindowsApp function
bool InitWindowsApp(HINSTANCE instanceHandle, int show)
{
	// Create a Windows class to describe the Window style
	WNDCLASS wc;

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = instanceHandle;
	wc.hIcon         = LoadIcon(0, IDI_APPLICATION);
	wc.hCursor       = LoadCursor(0, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = 0;
	wc.lpszClassName = L"BasicWndClass";


	// Now we need to register the Window style
	if(!RegisterClass(&wc))
	{
		MessageBox(0, L"RegisterClass FAILED", 0, 0);
		return false;
	}

	// With the Window style defined and registered we can now create the
	// window and sore the window handle in ghMainWnd.
	g_hMainWnd = CreateWindow(
		L"BasicWndClass",     // Registered WNDCLASS instance to use.
		L"Win32Basic",        // window title
		WS_OVERLAPPEDWINDOW,  // style flags
		CW_USEDEFAULT,        // x coordinate
		CW_USEDEFAULT,        // ycoordinate
		CW_USEDEFAULT,        // width
		CW_USEDEFAULT,        // height
		0,                    // parent window
		0,                    // menu handle
		instanceHandle,       // app instance
		0);                   // extra creation parameters

	if(g_hMainWnd == 0)
	{
		MessageBox(0, L"CreateWindow FAILED", 0, 0);
		return false;
	}

	// Widows is now created but is not automatically shown by default.
	// So call these funcions to display our window.
	ShowWindow(g_hMainWnd, show);
	UpdateWindow(g_hMainWnd);

	return true;
}
#pragma endregion

#pragma region Run function
int Run()
{
	// Classic example of a real-time message pump required for real-time
	// game processing.
	MSG msg = {0};

	while(msg.message != WM_QUIT)
	{
		// If we have any Window messages, process them.
		if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		else
		{
			// Do game processing here
			// GameMain()
		}
	}

	// Exit loop and return
	return (int)msg.wParam;
}
#pragma endregion

#pragma region WndProc message handler
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	// Handle some specific messages and if we do handle a message
	// we need to let Windows know by returning 0.
	switch( msg )
	{
	case WM_CREATE:
		// Do GameInit() stuff here
		return 0;

		// If ESC pressed then destroy the Window
	case WM_KEYDOWN:
		if( wParam == VK_ESCAPE )
			DestroyWindow(g_hMainWnd);
		return 0;

		// If Window has been destroyed then quit the application
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	// Forward any other messages we don't handle
	// to the default Windows procedure
	return DefWindowProc(hWnd, msg, wParam, lParam);
}
#pragma endregion
